/*
 * This file is a part of the SWFer project.
 *
 * Copyright (C) 2012 Michael Bradshaw <mjbshaw@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#ifndef BYTEREADER_HPP
#define BYTEREADER_HPP

#include "BasicTypes.hpp"
#include "TagHeader.hpp"
#include "SwfHeader.hpp"
#include "Packet.hpp"

#include <istream>
#include <string>
#include <vector>

namespace swfer
{

class ByteReader
{
public:
    ByteReader(std::istream& stream);
	
	// TODO: return bool based on stream validity?
	// TODO: test stream during reads for validity
    void read(int8_t& value);
    void read(int16_t& value);
    void read(int32_t& value);

    void read(uint8_t& value);
    void read(uint16_t& value);
    void read(uint32_t& value);

    void read(Rect& value);

    void read(Fixed16& value);
    void read(Fixed32& value);

    void read(TagHeader& value);
    void read(SwfHeader& value);
	void read(Packet& value);

	void read(std::string& value);

	void read(std::vector<char>& value);

	void skip(std::size_t bytes);

    template <uint8_t N>
    void read(BitField<N>& value)
	{
		value = 0;

		if (mask == 0) mask = -1;

		for (int remaining = value.bits; remaining > 0;)
		{
			int readerBits = bitLog2(mask) + 1;
			int read = std::min(readerBits, remaining);

			unsigned char realMask = mask & (mask << (readerBits - read));

			value <<= read;
			value |= (static_cast<unsigned char>(stream.peek()) & realMask) >> (readerBits - read);

			remaining -= read;
			mask >>= read;
			if (mask == 0 && remaining > 0)
			{
				mask = -1;
				stream.ignore();
			}
		}

		if (mask == 0) stream.ignore();
	}

private:
	std::istream& stream;
	
    unsigned char mask;
};

}

#endif
